package org.szgb.console.utils.excel;

import lombok.Getter;
import lombok.Setter;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Excel导出工具类
 *
 * @author szgb
 * @version 0.2.2024.10.29
 */
public class ExportExcel extends BaseExportExcel {
    /**
     * 表格样式对象
     */
    @Getter
    private XSSFCellStyle cellStyle;

    /**
     * 字体对象
     */
    @Getter
    private Font font;

    /**
     * 字体名称
     */
    @Setter
    private String fontName;
    /**
     * 字体大小
     */
    private short fontHeight;
    /**
     * 字体是否加粗
     */
    @Setter
    private boolean fontBold;


    public ExportExcel() {
        super();
        fontBold=false;
        refreshCellStyle();
    }

    /**
     * 创建单元格样式
     *
     * @return 返回创建的ExportExcel对象
     */
    public ExportExcel refreshCellStyle() {
        // 创建一个新的单元格样式对象
        cellStyle = getWb().createCellStyle();
        font = getWb().createFont();
        font.setFontName(fontName);
        font.setFontHeight(fontHeight);
        font.setBold(fontBold);
        cellStyle.setFont(font);
        return this;
    }

    /**
     * 设置单元格内容的对齐方式
     * 此方法允许调用者指定单元格内容的水平和垂直对齐方式，以精确控制表格中内容的显示位置
     *
     * @param horAlign 水平对齐方式，指定内容在单元格内的水平位置
     * @param verAlign 垂直对齐方式，指定内容在单元格内的垂直位置
     * @return 返回当前的ExportExcel对象，支持链式调用
     */
    public ExportExcel setCellAlignment(HorizontalAlignment horAlign, VerticalAlignment verAlign) {
        // 设置单元格内容的水平对齐方式
        cellStyle.setAlignment(horAlign);
        // 设置单元格内容的垂直对齐方式
        cellStyle.setVerticalAlignment(verAlign);
        return this;
    }


    /**
     * 合并单元格并设置边框（推荐）
     *
     * @param firstRow    起始行
     * @param lastRow     结束行
     * @param firstColumn 起始列
     * @param lastColumn  结束列
     * @return this
     */
    @Override
    public ExportExcel mergeCells(int firstRow, int lastRow, int firstColumn, int lastColumn) {
        // 1. 先合并
        super.mergeCells(firstRow, lastRow, firstColumn, lastColumn);

        // 2. 为合并区域外围的单元格设置边框
        for (int row = firstRow; row <= lastRow; row++) {
            Row r = getSheet().getRow(row);
            if (r == null) r = getSheet().createRow(row);

            for (int col = firstColumn; col <= lastColumn; col++) {
                Cell cell = r.getCell(col);
                if (cell == null) cell = r.createCell(col);

                cell.setCellStyle(cellStyle);
            }
        }

        return this;
    }

    /**
     * 合并单元格函数的重载版本，用于根据相对位置合并单元格
     * 此方法通过指定当前单元格的宽度和高度来合并单元格，而不是具体的起始和结束行列索引
     * 它提供了一种更直观的方式来合并单元格，特别是当用户更关心合并区域的大小而非具体位置时
     *
     * @param height 要合并的单元格的高度（行数）
     * @param width  要合并的单元格的宽度（列数）
     * @return 返回一个ExportExcel对象，允许进行链式调用或其他操作
     */
    @Override
    public ExportExcel mergeCells(int height, int width) {
        // 调用另一个mergeCells方法，传入当前行索引、当前行索引加上宽度、当前列索引、当前列索引加上高度
        // 这种设计允许通过相对位置来合并单元格，而不是每次都计算绝对的行列索引
        mergeCells(getCurrentRowIndex(), getCurrentRowIndex() + height - 1, getCurrentCellIndex(),
                getCurrentCellIndex() + width - 1);
        setCurrentCellIndex(getCurrentCellIndex()+width-1);
        return this;
    }

    /**
     * 创建并设置单元格
     * 此方法用于在当前行中创建一个新的单元格，并为其设置预定的样式和值。
     * 它依赖于外部定义的行对象和当前单元格索引，以确定新单元格的位置。
     *
     * @param value 要设置在新单元格中的字符串值
     * @return 返回当前的ExportExcel对象，支持链式调用
     */
    @Override
    public ExportExcel createCell(String value) {
        super.createCell(value);
        getCell().setCellStyle(cellStyle);
        return this;
    }

    /**
     * 批量创建Excel单元格并赋值
     * 此方法接收一个字符串数组，为每个字符串创建一个Excel单元格并赋值。
     * 它内部调用了 {@link #createCell(String)} 方法来逐个创建单元格。
     * 主要作用是简化多个单元格创建的流程，提高代码可读性和效率。
     *
     * @param values 可变参数，代表要创建的Excel单元格的值
     * @return 返回ExportExcel对象，支持链式调用
     */
    @Override
    public ExportExcel createCell(String... values) {
        // 遍历每个传入的字符串值
        for (String value : values) {
            // 调用createCell方法为当前值创建一个Excel单元格
            createCell(value);
        }
        // 返回ExportExcel对象实例，支持链式调用
        return this;
    }


    /**
     * 创建并设置日期单元格
     * 根据给定的日期和格式模式，将日期格式化为字符串，并创建一个包含该字符串的单元格
     * 主要用于在表格中创建日期列或行，其中日期以特定格式显示
     *
     * @param date    日期对象，表示要格式化和显示的日期
     * @param pattern 字符串，指定日期的格式模式，例如"yyyy-MM-dd"
     *                该模式用于确定日期的显示格式
     * @return 返回当前的ExportExcel对象，支持链式调用
     */
    public ExportExcel createCell(Date date, String pattern) {
        // 格式化日期对象为指定模式的日期字符串，并创建单元格
        createCell(new SimpleDateFormat(pattern, Locale.CHINA).format(date));
        return this;
    }

    public void setFontHeightInPoints(double i) {
        fontHeight = (short) (i * 20);
    }
}
